<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <p data-lake-id="u2b2ec519" id="u2b2ec519"><span data-lake-id="uda18ad54" id="uda18ad54" class="lake-fontsize-11" style="color: var(--yq-text-primary)">Copy-On-Write简称COW，是一种用于程序设计中的优化策略。</span><strong><span data-lake-id="u5de1c1ce" id="u5de1c1ce" class="lake-fontsize-11" style="color: var(--yq-text-primary)">其基本思路是，从一开始大家都在共享同一个内容，当某个人想要修改这个内容的时候，才会真正把内容Copy出去形成一个新的内容然后再改，这是一种延时懒惰策略。</span></strong></p>
  <p data-lake-id="uab1d4383" id="uab1d4383"><span data-lake-id="u580a3988" id="u580a3988" class="lake-fontsize-11" style="color: var(--yq-text-primary)">​</span><br></p>
  <p data-lake-id="u450d6169" id="u450d6169"><span data-lake-id="ud76ff1b5" id="ud76ff1b5" class="lake-fontsize-11" style="color: var(--yq-text-primary)">从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用，可以在非常多的并发场景中使用到。</span></p>
  <p data-lake-id="u6c61e485" id="u6c61e485"><span data-lake-id="u4434ee42" id="u4434ee42" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br>
    CopyOnWriteArrayList相当于线程安全的ArrayList，CopyOnWriteArrayList使用了一种叫写时复制的方法，当有新元素add到CopyOnWriteArrayList时，先从原有的数组中拷贝一份出来，然后在新的数组做写操作，写完之后，再将原来的数组引用指向到新数组。</span></p>
  <p data-lake-id="ucbae887e" id="ucbae887e"><span data-lake-id="udb8006c6" id="udb8006c6" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br>
    这样做的好处是我们可以对CopyOnWrite容器进行并发的读，而不需要加锁，因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想，读和写不同的容器。</span></p>
  <p data-lake-id="ud25b95b1" id="ud25b95b1"><span data-lake-id="u3c16a478" id="u3c16a478" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><strong><span data-lake-id="ufdc3e16c" id="ufdc3e16c" class="lake-fontsize-11" style="color: var(--yq-text-primary)">注意：CopyOnWriteArrayList的整个add操作都是在锁的保护下进行的。也就是说add方法是线程安全的。</span></strong></p>
  <p data-lake-id="uc36d5894" id="uc36d5894"><span data-lake-id="u259bb15b" id="u259bb15b" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br></span><strong><span data-lake-id="u8cd5d29d" id="u8cd5d29d" class="lake-fontsize-11" style="color: var(--yq-text-primary)">CopyOnWrite并发容器用于读多写少的并发场景。</span></strong><span data-lake-id="ud9447a0b" id="ud9447a0b" class="lake-fontsize-11" style="color: var(--yq-text-primary)">比如白名单，黑名单，商品类目的访问和更新场景。</span></p>
  <p data-lake-id="uc9f64287" id="uc9f64287"><span data-lake-id="u05910631" id="u05910631" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br>
    和ArrayList不同的是，它具有以下特性：</span></p>
  <p data-lake-id="u60d5c04c" id="u60d5c04c"><span data-lake-id="u5f64c577" id="u5f64c577" class="lake-fontsize-11" style="color: var(--yq-text-primary)"><br>
    支持高效率并发且是线程安全的<br>
    因为通常需要复制整个基础数组，所以可变操作（add()、set() 和 remove() 等等）的开销很大<br>
    迭代器支持hasNext(), next()等不可变操作，但不支持可变 remove()等操作<br>
    使用迭代器进行遍历的速度很快，并且不会与其他线程发生冲突。在构造迭代器时，迭代器依赖于不变的数组快照<br><br></span></p>
  <p data-lake-id="ua1706bfb" id="ua1706bfb" style="text-align: center"><span data-lake-id="u3045cc4f" id="u3045cc4f" class="lake-fontsize-11" style="color: var(--yq-text-caption)">若有收获，就点个赞吧</span></p>
  <p data-lake-id="u457946f0" id="u457946f0"><span data-lake-id="u083afcd7" id="u083afcd7"><br><br></span></p>
 </body>
</html>